package com.nsl.my_youlai.mystar.easy_excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.nsl.my_youlai.mystar.easy_excel.exception.ExcelParseException;
import com.nsl.my_youlai.mystar.easy_excel.model.ExcelReadCheck;
import com.nsl.my_youlai.mystar.easy_excel.model.ExcelReadResult;
import com.nsl.my_youlai.mystar.easy_excel.model.ExcelStringRecorde;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class NslUtilEasyExcel {


    /**
     * 该函数仅做excel的解析，不进行校验
     * @param excelPath excel path
     * @param tClass 拟转换成的class
     * @param sheetIndex sheet index
     * @param headLine 表头行数
     * @return
     * @param <T> ExcelReadResult 包含 解析结果，解析异常，表路径，sheetName
     * @throws ExcelParseException 解析异常时，抛出，一般为：和模板不一致
     */
    public static <T extends ExcelStringRecorde> ExcelReadResult<T> readExcelSheet2StringList(String excelPath, Class<T> tClass, int sheetIndex, int headLine ) throws ExcelParseException {
        ExcelReadResult<T> excelReadResult=new ExcelReadResult<T>();
        excelReadResult.setExcelPath(excelPath);

        ExcelReaderBuilder excelReaderBuilder=createExcelReaderBuilder(excelPath,excelReadResult,tClass);
        excelReaderBuilder.sheet(sheetIndex).headRowNumber(headLine).doRead();
        try{
            if(excelReadResult.getCheckList().size()>0){
                throw new ExcelParseException(excelPath,excelReadResult.getSheetName(),excelReadResult.getCheckList());
            }
        } finally {
            return excelReadResult;
        }

    }
    public static <T extends ExcelStringRecorde> ExcelReadResult<T> readExcelSheet2StringList(String excelPath,  Class<T> tClass) throws ExcelParseException {
       return readExcelSheet2StringList(excelPath,tClass,0,1);
    }

    public static <T extends ExcelStringRecorde> ExcelReadResult<T> readExcelSheet2StringList(String excelPath, Class<T> tClass, String sheetName, int headLine){
        ExcelReadResult<T> excelReadResult=new ExcelReadResult();

        ExcelReaderBuilder excelReaderBuilder=createExcelReaderBuilder(excelPath,excelReadResult,tClass);
        excelReaderBuilder.sheet(sheetName).headRowNumber(headLine).doRead();
        try{
            if(excelReadResult.getCheckList().size()>0){
                throw new ExcelParseException(excelPath,excelReadResult.getSheetName(),excelReadResult.getCheckList());
            }
        } finally {
            return excelReadResult;
        }

    }

    public static <T extends ExcelStringRecorde> ExcelReadResult<T> readExcelSheet2StringList(String excelPath,   String sheetName,Class<T> tClass){
        ExcelReadResult<T> excelReadResult=new ExcelReadResult();

        ExcelReaderBuilder excelReaderBuilder=createExcelReaderBuilder(excelPath,excelReadResult,tClass);
        excelReaderBuilder.sheet(sheetName).headRowNumber(1).doRead();
        return excelReadResult;
    }


    private static<T extends ExcelStringRecorde> ExcelReaderBuilder createExcelReaderBuilder(String excelPath,ExcelReadResult<T> excelReadResult, Class<T> tClass){
        List<T> voStringList=excelReadResult.getRecordList();
        List<ExcelReadCheck> excelReadCheckList=excelReadResult.getCheckList();
        ExcelReaderBuilder excelReaderBuilder= EasyExcel.read(excelPath, tClass, new ReadListener<T>() {
            /**
             * 单次缓存的数据量
             */
            public static final int BATCH_COUNT = 100;
            /**
             *临时存储
             */
            private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            @Override
            public void invoke(T data, AnalysisContext context) {
                data.setRowIndex(context.readRowHolder().getRowIndex()+1);
                //log.info("data = {} ",data);
                cachedDataList.add(data);
                voStringList.add(data);

//                try {
//                    ExcelImportValid.valid(data);
//                    //excelReadCheckList.add(new ExcelReadCheck(context.readRowHolder().getRowIndex(),"必填项ok"));
//                } catch (ExcelNullValueException e) {
//                    ExcelReadCheck excelReadCheck=new ExcelReadCheck();
//
//                    throw new RuntimeException("必填字段未填写");
//                }

                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    // 存储完成清理 list
                    cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }


            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                excelReadResult.setSheetName(context.readSheetHolder().getSheetName());
                saveData();
//

            }
            /**
             * 加上存储数据库
             */
            private void saveData() {

            }

            @Override
            public void onException(Exception exception, AnalysisContext context) {
                if (exception instanceof ExcelDataConvertException) {
                    ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
                    //log.error("数据为:{}",excelDataConvertException.getCellData().getData()==null);
                    String dataString=excelDataConvertException.getCellData().getData()==null?"null":excelDataConvertException.getCellData().getStringValue();
                    log.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                            excelDataConvertException.getColumnIndex(), dataString);
                    String msg=String.format("第{%d}行，第{%d}列解析异常，数据为:{%s}",excelDataConvertException.getRowIndex(),
                            excelDataConvertException.getColumnIndex(), dataString);
                    ExcelReadCheck excelReadCheck=new ExcelReadCheck(context.readRowHolder().getRowIndex(),exception.getMessage());
                    excelReadCheck.setMessage(msg);
                    excelReadCheckList.add(excelReadCheck);
                }

            }
        });

        return excelReaderBuilder;
    }

    public static<T extends ExcelStringRecorde> Map<String,String> getExcelSheetHead2PropMap(Class<T> tClass){
        Map<String,String> map=new HashMap<>();
        Field[] fields= tClass.getDeclaredFields();
        for (Field field : fields) {
            if(field.isAnnotationPresent(ExcelProperty.class)){
                ExcelProperty annotation=field.getAnnotation(ExcelProperty.class);
                String string[]=annotation.value();
                map.put(string[0],field.getName());
            }
        }
        return map;
    }

    public static<T extends ExcelStringRecorde> Map<String,String> getProp2ExcelSheetHeadMap(Class<T> tClass){
        Map<String,String> map=new HashMap<>();
        Field[] fields= tClass.getDeclaredFields();
        for (Field field : fields) {
            if(field.isAnnotationPresent(ExcelProperty.class)){
                ExcelProperty annotation=field.getAnnotation(ExcelProperty.class);
                String string[]=annotation.value();
                map.put(field.getName(),string[0]);
            }
        }
        return map;
    }
}
